home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / utilprn / hpdeskje.sit / HPDJet ƒ / PDEF1.c < prev    next >
C/C++ Source or Header  |  1989-04-02  |  20KB  |  649 lines

  1. /* 02.04.1989  amn  (latest edit) */
  2.  
  3. /* PDEF1.c  -  printer driver for Macintosh and HP DeskJet, spooling. */
  4.  
  5. /* Compiles into 'PDEF' resource, id 1, name ''. */
  6. /* We cannot use any global variables in this code.  However, the globals of the */
  7. /* low-level driver (XPrint) are available thru the handle 'dCtlStorage' in the */
  8. /* driver's device control entry. */
  9.  
  10. /* This resource is placed into the printer resource file */
  11. /* 'HP DeskJet', type 'PRER', creator 's89^' as */
  12. /* 'PDEF' 1 '' by 'PRER_Builder' utility program.  This utility adds a small jump */
  13. /* table in front of the code produced by LightspeedC. */
  14.  
  15. /* These procedures handle spool file recording... */
  16.  
  17. /* Authors:  Ari Mujunen (amn@hutcs.hut.fi) and Olli Arnberg (oar@hutcs.hut.fi). */
  18. /* Copyright Ari Mujunen, Olli Arnberg 1989. */
  19. /* You may redistribute the driver (=printer resource file, source files, */
  20. /* documentation file(s), and the file 'Copyright and Source Offer') */
  21. /* only _non-commercially_ and _in its entirety_. */
  22. /* See the file 'Copyright and Source Offer' and/or documentation for details. */
  23. /* Acknowledgements:  Special thanks to Mr. Earle R. Horton for his 'Daisy' */
  24. /* daisywheel printer driver and its source code published in 'MacTutor', Nov-Dec 1987. */
  25. /* This driver served as a basis and inspiration for our work.  It also */
  26. /* proofed that a Macintosh printer driver can be done despite the lack of */
  27. /* documentation from Apple. */
  28.  
  29. /* Change history: */
  30. /* Version  When        Who      Why */
  31. /* 2.0      09.12.1988  amn      Original rewrite. */
  32. /*          11.12.1988  amn      Cleaning up. */
  33. /*          15.12.1988  amn      Differentiate between our idle proc */
  34. /*                               that of application. */
  35. /*          25.02.1989  amn      Accidentally locked PDEF 0 instead of 1. */
  36. /*          10.03.1989  amn      Saving the length of each string drawn */
  37. /*                               as a picture comment. */
  38. /*          25.03.1989  amn      Removing global file refNums. */
  39. /*          28.03.1989  amn      Settable printer origin. */
  40. /*          30.03.1989  amn,oar  Option-OK causes spool file to be named and */
  41. /*                               saved for subsequent batch printing. */
  42. /*          31.03.1989  amn      More permanent spool file. */
  43. /* 2.1      02.04.1989  amn,oar  Released version. */
  44.  
  45.  
  46. #include "common_mac_includes.h"
  47.  
  48. /* Mac OS includes specific to this module: */
  49. #include <ToolboxUtil.h>
  50. #include <StdFilePkg.h>
  51.  
  52.  
  53. #include "prglobals.h"
  54.  
  55. #include "procedures_for_PDEF1.c"
  56. #include "procedures_for_PDEF5.c"  /* idle proc is here */
  57.  
  58.  
  59.  
  60. /* Function prototypes. */
  61.  
  62. /* Procedure dispatcher. */
  63. void main(int);
  64.  
  65. /* Initializes a specialized grafPort for printing.  Opens spool file. */
  66. pascal TPPrPort myPrOpenDoc(THPrint, TPPrPort, Ptr);
  67.  
  68. /* Disposes the printing grafPort.  Updates spool file header on disk.  Closes spool file. */
  69. pascal void myPrCloseDoc(TPPrPort);
  70.  
  71. /* Reinitializes the printing grafPort. */
  72. pascal void myPrOpenPage(TPPrPort, TPRect);
  73.  
  74. /* Updates spool file header in memory. */
  75. pascal void myPrClosePage(TPPrPort);
  76.  
  77.  
  78. /* Replaces the standard QuickDraw low-level procedure for drawing text. */
  79. pascal void myStdText(int, Ptr, Point, Point);
  80.  
  81. /* Used to call standard QD text-drawing procedure.  We use prototypes... */
  82. pascal void CallPascal(int, Ptr, Point, Point, Ptr);
  83.  
  84. pascal void putPICTData(Ptr, int);
  85.  
  86. void copystr(StringPtr, StringPtr);
  87.  
  88.  
  89.  
  90. /* Function definitions. */
  91.  
  92.  
  93. void
  94. main(routineSelector)
  95. int routineSelector;
  96. {
  97.     /* The jump table code inserted before our code resource by 'PRER_Builder' */
  98.     /* utility program pushes a word onto stack indicating which routine is called. */
  99.     /* We pop it off the stack and select an appropriate routine. */
  100.     
  101.     switch(routineSelector) {
  102.         case 0:
  103.             asm {
  104.                 unlk a6  ;; LSC generates an 'link' instruction to access parameters
  105.                 move.l (a7)+, d0  ;; pop return address to our jump table code (discarded)
  106.                 move.w (a7)+, d0  ;; pop argument 'routineSelector'
  107.                 jmp myPrOpenDoc
  108.             }
  109.         case 1:
  110.             asm {
  111.                 unlk a6
  112.                 move.l (a7)+, d0
  113.                 move.w (a7)+, d0
  114.                 jmp myPrCloseDoc
  115.             }
  116.         case 2:
  117.             asm {
  118.                 unlk a6
  119.                 move.l (a7)+, d0
  120.                 move.w (a7)+, d0
  121.                 jmp myPrOpenPage
  122.             }
  123.         case 3:
  124.             asm {
  125.                 unlk a6
  126.                 move.l (a7)+, d0
  127.                 move.w (a7)+, d0
  128.                 jmp myPrClosePage
  129.             }
  130.     }  /* switch */
  131.     
  132.     /* We should not arrive here; Printing Manager has called a non-existent routine. */
  133.     SysError(5);  /* check bounds trap ??? */
  134. }  /* main */
  135.  
  136.  
  137. /* 
  138. This function is supposed to return a pointer to a specialized GrafPort (a TPrPort) customized
  139. for printing. Due to the paucity of documentation on how to go about this, I do not know whether
  140. I am going about this in exactly the right way, but I sure hope so. I set portBits.bounds for 
  141. the port to the empty Rect (0,0,0,0).
  142. Other tasks: save a copy of the user print record in the printer resource file
  143. to remember user's last choices in job dialog (resolution etc.).
  144. */
  145.  
  146.  
  147. #define DEBUG_OPEN_PRINT_RECORD
  148.  
  149. pascal TPPrPort
  150. myPrOpenDoc(hPrint, pPrPort, pIOBuf)
  151. THPrint  hPrint;
  152. TPPrPort pPrPort;
  153. Ptr pIOBuf;
  154. {
  155.     TPPrPort thisPort;
  156.     ptXprintGlobals xPrintGlobals;
  157.     Boolean spoolFileExistedBeforeThisOpenDoc;
  158.     OSErr retCode;
  159.     
  160.     {  /* Lock this code resource in memory (Printing Manager should do this, but...). */
  161.         Handle    us;
  162.         
  163.         us = (Handle)GetResource('PDEF', 1);
  164.         if (us == nil) {
  165.             PrintErr = ResError();
  166.             return(nil);
  167.         }
  168.         HLock(us);
  169.     }
  170.  
  171.     if (pPrPort == nil) {  /* printing GrafPort NOT preallocated */
  172.         if ((thisPort = (TPPrPort)NewPtr((long)sizeof(TPrPort))) == nil) {
  173.             PrintErr = iMemFullErr;
  174.             return(nil);
  175.         }
  176.         thisPort->fOurPtr = TRUE;
  177.     }
  178.     else {  /* printing GrafPort already preallocated */
  179.         /* We cannot check the size of the port given to us, since it can be */
  180.         /* in application globals, not necessarily a block reserved with NewPtr. */
  181.         thisPort = pPrPort;
  182.         thisPort->fOurPtr = FALSE;
  183.     }
  184.     
  185.     xPrintGlobals = GET_XPRINT_GLOBALS;
  186.     
  187.     xPrintGlobals->hSpoolFileHeader = nil;
  188.     
  189.     
  190.     /* Initialize GrafPort */
  191.     OpenPort(&thisPort->gPort);  /* could this cause a Memory Manager error ??? */
  192.     setRectsAndRgns(thisPort, hPrint);
  193.     
  194.     /* Determine the name of the spool file. */
  195.     if (!xPrintGlobals->spoolFileAlreadyNamed) {
  196.         StringHandle defaultSpoolFileNameHandle;
  197.         StringPtr defaultSpoolFileNamePtr;
  198.         Str255 defaultSpoolFileName;
  199.         
  200.         /* Page range etc. are available in global print record. */
  201.         xPrintGlobals->printRecord = **hPrint;
  202.         
  203.         /* Default name from either print record or from resource. */
  204.         if (xPrintGlobals->printRecord.prJob.pFileName != nil) {
  205.             defaultSpoolFileNamePtr = xPrintGlobals->printRecord.prJob.pFileName;
  206.             /* We assume volume number is ok. */
  207.         }
  208.         else {
  209.             defaultSpoolFileNameHandle = GetString(RESID_OWNED_BY_PDEF + 1);
  210.             if (defaultSpoolFileNameHandle == nil)
  211.                 copystr((StringPtr)"\pPrint File", defaultSpoolFileName);
  212.             else {
  213.                 LoadResource(defaultSpoolFileNameHandle);
  214.                 copystr(*defaultSpoolFileNameHandle, defaultSpoolFileName);
  215.                 HPurge(defaultSpoolFileNameHandle);
  216.             }
  217.             defaultSpoolFileNamePtr = defaultSpoolFileName;
  218.             xPrintGlobals->printRecord.prJob.iFileVol = 0;  /* default volume ??? */
  219.         }
  220.         
  221.         if (xPrintGlobals->spoolFileIsNamedAndPermanent) {
  222.             Point where;
  223.             SFReply reply;
  224.             StringHandle hPrompt;
  225.             int saveVRefNum;
  226.             Str255 dummySaveVolName;
  227.             
  228.             /* Set default volume for StdFile dialog starting point. */
  229.             if ((retCode = GetVol(&dummySaveVolName, &saveVRefNum)) != noErr)
  230.                 goto cleanUp;
  231.             if ((retCode = SetVol(nil, xPrintGlobals->printRecord.prJob.iFileVol)) != noErr)
  232.                 goto cleanUp;
  233.             
  234.             where.v = where.h = 100;
  235.             /* Get prompt; (RESID+2 is used by SuperSpool...) */
  236.             if ((hPrompt = GetString(RESID_OWNED_BY_PDEF + 3)) != nil) {
  237.                 HLock(hPrompt);
  238.                 SFPutFile(
  239.                     where,
  240.                     *hPrompt,
  241.                     defaultSpoolFileNamePtr,  /* original name */
  242.                     nil,
  243.                     &reply
  244.                 );
  245.                 HUnlock(hPrompt);
  246.                 HPurge(hPrompt);
  247.             }
  248.             else {
  249.                 SFPutFile(
  250.                     where,
  251.                     (StringPtr)"\pSave spool file as:",
  252.                     defaultSpoolFileName,  /* original name */
  253.                     nil,
  254.                     &reply
  255.                 );
  256.             }
  257.             
  258.             if ((retCode = SetVol(nil, saveVRefNum)) != noErr)
  259.                 goto cleanUp;  /* default volume is probably messed up... */
  260.             
  261.             if (reply.good) {
  262.                 copystr(reply.fName, defaultSpoolFileName);
  263.                 defaultSpoolFileNamePtr = defaultSpoolFileName;
  264.                 xPrintGlobals->printRecord.prJob.iFileVol = reply.vRefNum;
  265.                 xPrintGlobals->spoolFileAlreadyNamed = TRUE;
  266.             }
  267.             else {  /* User clicked Cancel, resume normal printing. */
  268.                 xPrintGlobals->spoolFileIsNamedAndPermanent = FALSE;
  269.                 xPrintGlobals->spoolFileAlreadyNamed = FALSE;
  270.             }
  271.         }  /* if permanent spool file */
  272.         
  273.         /* Now we copy the spool file name from either application memroy */
  274.         /* or our temp variable to the global spoolFileName; global */
  275.         /* print record reJob.pFileName field points to this variable. */
  276.         {
  277.             copystr(defaultSpoolFileNamePtr, xPrintGlobals->spoolFileName);
  278.             xPrintGlobals->printRecord.prJob.pFileName = xPrintGlobals->spoolFileName;
  279.             /* xPrintGlobals->printRecord.prJob.iFileVol is already ok */
  280.             xPrintGlobals->printRecord.prJob.bFileVers = 0;
  281.         }
  282.     }  /* end if has to determine spool file name */
  283.     
  284.     /* Open spool file, set its file type ('PFIL''^89s'). */
  285.     /* '^89s' is the signature of the batch printing utility, BatchPrint. */
  286.     retCode = Create(
  287.         xPrintGlobals->printRecord.prJob.pFileName,
  288.         xPrintGlobals->printRecord.prJob.iFileVol,
  289.         '^89s',
  290.         'PFIL'
  291.     );
  292.     spoolFileExistedBeforeThisOpenDoc = (retCode == dupFNErr);
  293.     if (!((retCode == noErr) || (retCode == dupFNErr)))
  294.         goto cleanUp;
  295.     
  296.     retCode = FSOpen(
  297.         xPrintGlobals->printRecord.prJob.pFileName,
  298.         xPrintGlobals->printRecord.prJob.iFileVol,
  299.         &(xPrintGlobals->spoolFileRefNum)
  300.     );
  301.     if (retCode != noErr)
  302.         goto deleteAndCleanUp;
  303.     
  304.     /* Allocate memory buffer for page directory. */
  305.     if ((xPrintGlobals->hSpoolFileHeader = (THPfHeader)NewHandle((long)sizeof(TPfHeader))) == nil) {
  306.         retCode = iMemFullErr;
  307.         goto closeAndDeleteAndCleanUp;
  308.     }
  309.     
  310.     /* Add pages to existing spool file _or_ initialize new spool file. */
  311.     if (spoolFileExistedBeforeThisOpenDoc) {
  312.         long count;
  313.                     
  314.         count = sizeof(TPfHeader);
  315.         HLock(xPrintGlobals->hSpoolFileHeader);
  316.         retCode = FSRead(xPrintGlobals->spoolFileRefNum, &count, *(xPrintGlobals->hSpoolFileHeader));
  317.         HUnlock(xPrintGlobals->hSpoolFileHeader);
  318.         if (retCode != noErr)
  319.             goto disposAndCloseAndDeleteAndCleanUp;
  320.         
  321.         /* Position file to logical end to receive additional pages. */
  322.         if ((retCode = SetFPos(xPrintGlobals->spoolFileRefNum, fsFromLEOF, 0L)) != noErr)
  323.             goto disposAndCloseAndDeleteAndCleanUp;
  324.     }
  325.     else {  /* Prepend print spool file header for PFIL file format: */
  326.         long count;
  327.         int i;
  328.         
  329.         /* Initialize header to current print record and all zeroes. */
  330.         for (i=0;i<sizeof(TPfHeader);i++)
  331.             ((unsigned char *)(*xPrintGlobals->hSpoolFileHeader))[i] = (unsigned char)0;
  332.         (*xPrintGlobals->hSpoolFileHeader)->print = **hPrint;
  333.         (*xPrintGlobals->hSpoolFileHeader)->print.prJob.pIdleProc = nil;
  334.         (*xPrintGlobals->hSpoolFileHeader)->print.prJob.pFileName = nil;
  335.         (*xPrintGlobals->hSpoolFileHeader)->print.prJob.iFileVol = 0;
  336.             
  337.         count = sizeof(TPfHeader);
  338.         HLock(xPrintGlobals->hSpoolFileHeader);
  339.         retCode = FSWrite(xPrintGlobals->spoolFileRefNum, &count, *(xPrintGlobals->hSpoolFileHeader));
  340.         HUnlock(xPrintGlobals->hSpoolFileHeader);
  341.         if (retCode != noErr)
  342.             goto disposAndCloseAndDeleteAndCleanUp;
  343.             
  344. #define NUMBER_OF_THIS_PDEF 1
  345. #include "save_last_used.c"
  346. #undef NUMBER_OF_THIS_PDEF
  347.     
  348.         /* If application has not requested an own idle procedure, we set our default one. */
  349.         if (xPrintGlobals->printRecord.prJob.pIdleProc == nil) {
  350.             xPrintGlobals->printRecord.prJob.pIdleProc = (ProcPtr)checkForCommandPeriod;
  351.             xPrintGlobals->applicationOwnsIdleProc = FALSE;
  352.         }
  353.         else
  354.             xPrintGlobals->applicationOwnsIdleProc = TRUE;
  355.         /* For example WriteNow seems to rely on 'pIdleProc' being non-nil. */
  356.         /* That is why we must set it -- although we don't call idle proc */
  357.         /* ourselves, application might be that friendly and do it for us. */
  358.             
  359.     }  /* else spool file is new */
  360.  
  361.     /* High-level printing code always counts pages from 1 (IM II-156). */
  362.     xPrintGlobals->pageCounter = 1;
  363.  
  364. #ifdef DEBUG_OPEN_PRINT_RECORD
  365.     /* Print out the contents of the print record to find out what applications store into it. */
  366. #endif DEBUG_OPEN_PRINT_RECORD
  367.  
  368.     retCode = noErr;
  369. cleanUp:
  370.     PrintErr = retCode;
  371.     return(thisPort);
  372.     /* An application conforming to IM II-155 will call 'PrCloseDoc' regardless the value of */
  373.     /* 'PrError'.  It is 'PrCloseDoc's duty to free 'thisPort'. */
  374.  
  375. disposAndCloseAndDeleteAndCleanUp:
  376.     DisposHandle(xPrintGlobals->hSpoolFileHeader);    
  377.     xPrintGlobals->hSpoolFileHeader = nil;
  378. closeAndDeleteAndCleanUp:
  379.     (void)FSClose(xPrintGlobals->spoolFileRefNum);
  380. deleteAndCleanUp:
  381.     (void)FSDelete(
  382.         xPrintGlobals->printRecord.prJob.pFileName,
  383.         xPrintGlobals->printRecord.prJob.iFileVol
  384.     );
  385.     goto cleanUp;
  386. }  /* myOpenDoc */
  387.  
  388.  
  389. pascal void
  390. myPrCloseDoc(pPrPort)
  391. TPPrPort pPrPort;
  392. {
  393.     ptXprintGlobals xPrintGlobals;
  394.     OSErr retCode;    
  395.     
  396.     if (pPrPort == nil)  /* if opening did not succeed, we do nothing */
  397.         return;
  398.         
  399.     xPrintGlobals = GET_XPRINT_GLOBALS;
  400.     
  401.     if (PrintErr != noErr) {  /* something has gone wrong, we must clean up our port */
  402.         retCode = PrintErr;
  403.         goto disposAndCloseAndDeleteAndCleanUp;
  404.     }
  405.     
  406.     /* Now we are at the end of last page spooled, mark logical end of file. */
  407.     {
  408.         long filePosition;
  409.         
  410.         if ((retCode = GetFPos(xPrintGlobals->spoolFileRefNum, &filePosition)) != noErr)
  411.             goto disposAndCloseAndDeleteAndCleanUp;
  412.         if ((retCode = SetEOF(xPrintGlobals->spoolFileRefNum, filePosition)) != noErr)
  413.             goto disposAndCloseAndDeleteAndCleanUp;
  414.     }
  415.     
  416.     /* Update print spool file header (page directory) for PFIL file format: */
  417.     {
  418.         long count;
  419.         
  420.         retCode = SetFPos(xPrintGlobals->spoolFileRefNum, fsFromStart, 0L);
  421.         if (retCode != noErr)
  422.             goto disposAndCloseAndDeleteAndCleanUp;
  423.         
  424.         count = sizeof(TPfHeader);
  425.         HLock(xPrintGlobals->hSpoolFileHeader);
  426.         retCode = FSWrite(xPrintGlobals->spoolFileRefNum, &count, *xPrintGlobals->hSpoolFileHeader);
  427.         HUnlock(xPrintGlobals->hSpoolFileHeader);
  428.         if (retCode != noErr)
  429.             goto disposAndCloseAndDeleteAndCleanUp;
  430.         
  431.         DisposHandle(xPrintGlobals->hSpoolFileHeader);
  432.     }
  433.  
  434.     retCode = FSClose(xPrintGlobals->spoolFileRefNum);
  435.     if (retCode != noErr)
  436.         goto deleteAndCleanUp;
  437.     
  438.     retCode = noErr;
  439. cleanUp:
  440.     PrintErr = retCode;
  441.     ClosePort(pPrPort);
  442.     if (pPrPort->fOurPtr)  /* if we allocated the port, we have to deallocate it too */
  443.         DisposPtr(pPrPort);
  444.     return;
  445.  
  446. disposAndCloseAndDeleteAndCleanUp:
  447.     if (xPrintGlobals->hSpoolFileHeader == nil)
  448.         goto cleanUp;
  449.     DisposHandle(xPrintGlobals->hSpoolFileHeader);    
  450.     xPrintGlobals->hSpoolFileHeader = nil;
  451. closeAndDeleteAndCleanUp:
  452.     (void)FSClose(xPrintGlobals->spoolFileRefNum);
  453. deleteAndCleanUp:
  454.     (void)FSDelete(
  455.         xPrintGlobals->printRecord.prJob.pFileName,
  456.         xPrintGlobals->printRecord.prJob.iFileVol
  457.     );
  458.     goto cleanUp;
  459. }  /* myCloseDoc */
  460.  
  461.  
  462. pascal void
  463. myPrOpenPage(pPrPort, pPageFrame)
  464. TPPrPort pPrPort;
  465. TPRect pPageFrame;
  466. {
  467.     ptXprintGlobals xPrintGlobals;
  468.     OSErr retCode;
  469.     
  470.     if (pPrPort == nil)
  471.         /* There is not much we can do; */
  472.         /* the application will 'print' into a very odd GrafPort. */
  473.         return;
  474.     
  475.     /* If (PrintErr != noErr), we assume we have a port to satisfy the application, */
  476.     /* but something has gone awry with the spool file. */
  477.         
  478.     
  479.     xPrintGlobals = GET_XPRINT_GLOBALS;
  480.     
  481.     /* Port is returned to initial state (as initialized in OpenDoc). */
  482.     InitPort(pPrPort);
  483.     {
  484.         TPPrint pPrint;
  485.     
  486.         pPrint = &xPrintGlobals->printRecord;
  487.         setRectsAndRgns(pPrPort, &pPrint);
  488.     }
  489.     
  490.     xPrintGlobals->hPagePicture = nil;
  491.     
  492.     /* For pages not to be printed, return a GrafPort which does not record a QD-picture. */
  493.     if ((xPrintGlobals->pageCounter < xPrintGlobals->printRecord.prJob.iFstPage)
  494.         || (xPrintGlobals->pageCounter > xPrintGlobals->printRecord.prJob.iLstPage)
  495.         || (PrintErr != noErr)) {
  496.         return;
  497.     }
  498.     
  499.     /* Open QD-picture using either page rectangle */
  500.     /* or application-specified rectangle as picture frame. */
  501.     {
  502.         Rect pictureFrame;
  503.         
  504.         if (pPageFrame != nil)
  505.             pictureFrame = *pPageFrame;  /* application wants to scale */
  506.         else
  507.             pictureFrame = xPrintGlobals->printRecord.prInfo.rPage;
  508.             
  509.         xPrintGlobals->hPagePicture = OpenPicture(&pictureFrame);
  510.         if (xPrintGlobals->hPagePicture == nil) {
  511.             PrintErr = iMemFullErr;
  512.             return;
  513.         }
  514.     }
  515.     
  516.     /* Update page directory in memory (page picture starting offset). */
  517.     {
  518.         long position;
  519.         int i;
  520.         
  521.         retCode = GetFPos(xPrintGlobals->spoolFileRefNum, &position);
  522.         if (retCode != noErr) {
  523.             PrintErr = retCode;
  524.             return;
  525.         }
  526.         
  527.         /* Store start offset in spool file according to the header page number. */
  528.         i = (++((*xPrintGlobals->hSpoolFileHeader)->pfPgDir.iPages));
  529.         (*xPrintGlobals->hSpoolFileHeader)->pfPgDir.lPgPos[i]
  530.             = position;
  531.     }
  532.     
  533.     /* Write the beginning of page picture data to spool file. */
  534.     {
  535.         long count;
  536.         
  537.         count = (long)sizeof(Picture);
  538.         HLock(xPrintGlobals->hPagePicture);
  539.         retCode = FSWrite(xPrintGlobals->spoolFileRefNum, &count, *xPrintGlobals->hPagePicture);
  540.         HUnlock(xPrintGlobals->hPagePicture);
  541.         if (retCode != noErr) {
  542.             PrintErr = retCode;
  543.             return;
  544.         }
  545.     }
  546.     
  547.     /* Set our own procedure for storing picture data directly to spool file. */
  548.     SetStdProcs(&pPrPort->gProcs);
  549.     pPrPort->gPort.grafProcs = &pPrPort->gProcs;
  550.     pPrPort->gProcs.textProc = (QDPtr)myStdText;
  551.     pPrPort->gProcs.putPicProc = (QDPtr)putPICTData;
  552.  
  553.     ClipRect(&pPrPort->gPort.portRect);  /* ImageWriter records this, so do we. */
  554.     
  555.     /* Finders 4.1 & 6.0 seem to rely on printing GrafPort's font being application font. */
  556.     /* Turbo Pascal 1.1 seems not to like this, though. */
  557.     TextFont(applFont);
  558. }  /* myPrOpenPage */
  559.  
  560.  
  561. pascal void
  562. myPrClosePage(pPrPort)
  563. TPPrPort pPrPort;
  564. {
  565.     ptXprintGlobals xPrintGlobals;
  566.     
  567.     if (pPrPort == nil)  /* Guard against stupid applications */
  568.         return;
  569.     
  570.     xPrintGlobals = GET_XPRINT_GLOBALS;
  571.     
  572.     /* If we were recording QD-picture to disk, we close it. */
  573.     if (xPrintGlobals->hPagePicture != nil) {
  574.         ClosePicture();  /* close picture to get the end_of_picture -mark to disk */
  575.         pPrPort->gPort.grafProcs =     nil;  /* no more special drawing procs */
  576.         KillPicture(xPrintGlobals->hPagePicture);
  577.         xPrintGlobals->hPagePicture = nil;
  578.     }
  579.     
  580.     /* If the capacity of spool file header is exceeded, cancel printing. */
  581.     if (((*xPrintGlobals->hSpoolFileHeader)->pfPgDir.iPages) >= iPfMaxPgs)
  582.         PrintErr = iPrAbort;
  583.     
  584.     xPrintGlobals->pageCounter++;
  585. }  /* myClosePage */
  586.  
  587.  
  588. pascal void
  589. myStdText(byteCount, textBuffer, numer, denom)
  590. int        byteCount;
  591. Ptr    textBuffer;
  592. Point    numer, denom;
  593. {
  594.     htApplicationComment lengthComment;
  595.     QDProcs stdProcs;
  596.     
  597.     if ((lengthComment = (htApplicationComment)NewHandle(sizeof(tApplicationComment))) != nil) {
  598.         (*lengthComment)->applicationSignature = 's89^';
  599.         (*lengthComment)->localKind = 0;
  600.         (*lengthComment)->originalLengthOfNextTextInPixels =
  601.             TextWidth(textBuffer, 0, byteCount);
  602.             /* Hmm, what about 'numer' and 'denom' ? */
  603.             /* Seems to work ok though, even when QD has to scale */
  604.             /* the font when recording PICT. */
  605.         
  606.         PicComment(100, sizeof(tApplicationComment), lengthComment);
  607.         DisposHandle(lengthComment);
  608.     }
  609.     /* Finally, draw text using standard procedure. */
  610.     SetStdProcs(&stdProcs);
  611.     CallPascal(byteCount, textBuffer, numer, denom, stdProcs.textProc);
  612. }  /* myStdText */
  613.  
  614.  
  615. pascal void
  616. putPICTData(dataPtr, byteCount)
  617. Ptr dataPtr;
  618. int byteCount;
  619. {
  620.     long count;
  621.     ptXprintGlobals xPrintGlobals;
  622.     OSErr retCode;
  623.     
  624.     if (PrintErr == noErr) {
  625.         count = byteCount;
  626.         xPrintGlobals = GET_XPRINT_GLOBALS;
  627.         retCode = FSWrite(xPrintGlobals->spoolFileRefNum, &count, dataPtr);
  628.         if (retCode != noErr)
  629.             PrintErr = retCode;
  630.     }
  631. }  /* putPICTData */
  632.  
  633.  
  634. void
  635. copystr(src, dst)
  636. StringPtr src, dst;
  637. /* This is for copying PASCAL strings (simple) */
  638. {
  639.     asm {
  640.         clr.l d0
  641.         move.l src,a0
  642.         move.l dst,a1
  643.         move.b (a0),d0
  644.         loop:
  645.         move.b (a0)+,(a1)+
  646.         dbra d0,@loop
  647.     }
  648. }
  649.